home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 5 / MacMania 5.toast / / Tools&Utilities / BibTeX ƒ / BibTeXAlphaScripts.tcl < prev    next >
Text File  |  1996-11-19  |  13KB  |  421 lines

  1. ## -*-Tcl-*-
  2.  # ###################################################################
  3.  #    BibTeX for MacOS -- scripts for GURL interaction with Alpha.
  4.  # 
  5.  #    FILE: "BibTeXAlphaScripts.tcl"
  6.  #                                      created: 13/11/96    {1:05:50 am} 
  7.  #                                  last update: 19/11/96 {2:50:03 pm} 
  8.  #    Author:    Vince Darley
  9.  #    E-mail:    <vince@das.harvard.edu>
  10.  #      mail:    Division of    Applied    Sciences, Harvard University
  11.  #            Oxford Street, Cambridge MA    02138, USA
  12.  #       www:    <http://www.fas.harvard.edu/~darley/>
  13.  #    
  14.  #    INSTALLATION PROCEDURE:
  15.  #    
  16.  #    Add    the following line to your "prefs.tcl" (a file located in Alpha's      
  17.  #  preferences folder inside your Preferences folder in your System folder):
  18.  #  
  19.  #      eventHandler GURL GURL GURLHandler
  20.  #  
  21.  #  This declares an event handler so we receive GURL events from
  22.  #  the BibTeX application (Note: do not copy the '#' at the beginning of
  23.  #  the line).
  24.  # 
  25.  #  Then move this file to the 'UserCode' folder inside the 'Tcl' folder
  26.  #  which is located in the same place as the application Alpha.  Now
  27.  #  open Alpha, hit 'cmd-Y', and select 'Rebuild Tcl Indices' from the
  28.  #  menu.  After a minute or so, you can quit Alpha, and installation is
  29.  #  complete.
  30.  # 
  31.  #  The only further choice you have is the value of the variable
  32.  #  Bib_AutoIndex, which you can set below.
  33.  # 
  34.  #  modified by  rev reason
  35.  #  -------- --- --- -----------
  36.  #  13/11/96 VMD 1.0 original -- for use with BibTeX 1.1.4
  37.  # ###################################################################
  38.  ##
  39.  
  40.  
  41. # 0=never make index (except manually)
  42. # 1=ask user when necessary 
  43. # 2=always remake when necessary
  44. set Bib_AutoIndex 1
  45.  
  46. ## 
  47.  # -------------------------------------------------------------------------
  48.  #     
  49.  # "GURLHandler" --
  50.  #    
  51.  #    Handle general GURL    events by extracting the type 'ftp', 'http',…
  52.  #    and    calling    a procedure    ${type}GURLHandler with    a single parameter
  53.  #    which is the extracted resource.  Can be put to more general use.
  54.  # -------------------------------------------------------------------------
  55.  ##
  56. proc GURLHandler {msg} {
  57.     if ![regsub {.*“(.*)”.*} $msg {\1} gurl] {
  58.         alertnote "Didn't understand GURL: $msg"
  59.         return
  60.     }
  61.     set GURLtype [lindex [split $gurl ":"] 0]
  62.     set GURLvalue [string range $gurl [expr 1+[string length $GURLtype]] end]
  63.     ${GURLtype}GURLHandler $GURLvalue
  64. }
  65.  
  66. ## 
  67.  # -------------------------------------------------------------------------
  68.  #     
  69.  # "bibresultGURLHandler" --
  70.  #    
  71.  #    Handle 'bibresult' GURLs, as sent by the application BibTeX.  These
  72.  #    goto bibliography files, errors, warnings etc.    We do the parsing here.
  73.  #    See    BibTeX's readme    file for the syntax    of the message.
  74.  # -------------------------------------------------------------------------
  75.  ##
  76. proc bibresultGURLHandler {msg} {
  77.     # Extract base .aux file name (full path description or 'Unknown')
  78.     set bpos [string first ".aux:" $msg]
  79.     set base_aux [string range $msg 0 [incr bpos 3]]
  80.     # Get rest of message
  81.     set msg [string range $msg [incr bpos 2] end]
  82.     if [regsub {.*: ([^.]+.(aux|bst|bib))} $msg {\1} filename] {
  83.         openTeXFile "$filename"
  84.         return
  85.     }
  86.     
  87.     switch [lindex [split $msg "-"] 0] {
  88.       "Warning" {
  89.           # extract warning type and find the entry
  90.           # the last item is the entry (minus quotes possibly)
  91.           set msg [string range $msg 9 end]
  92.           set llen [llength $msg]
  93.           set item [string trim [lindex $msg [incr llen -1]] {"}]
  94.           set warning [lrange $msg 0 [incr llen -1]]
  95.           if { $warning == "I didn't find a database entry for" } {
  96.               # no entry exists, prompt to make one
  97.               set choice [prompt  \
  98.                   "No entry '$item' exists.  What do you want to do?" \
  99.                   "New entry" "Choices" \
  100.                   "New entry" "New entry in new bibliography file" \
  101.                   "Add .bib file to \\bibliography\{…\}" ]
  102.               switch $choice {
  103.                 "New entry" {
  104.                     # need to pick a .bib file
  105.                     set bibfile [bibPickBibliography 1 \
  106.                         "Select a bibliography file to which to add an entry"]
  107.                     openTeXFile $bibfile
  108.                     global entryNames
  109.                     bibFormatSetup
  110.                     newEntry [listpick -p "Which type of entry?" $entryNames]
  111.                     insertText $item
  112.                     nextTabStop
  113.                 }
  114.                 "New entry in new bibliography file" {
  115.                 set bibfile [putfile "Save new bibliography as…" ".bib"]
  116.                 if {$bibfile == ""} {
  117.                     error "No bibliography file selected."
  118.                 } else {
  119.                     new -n $bibfile
  120.                 }        
  121.                     global entryNames
  122.                     bibFormatSetup
  123.                     newEntry [listpick -p "Which type of entry?" $entryNames]
  124.                     insertText $item
  125.                     nextTabStop
  126.                 }
  127.                 "Add .bib file to \\bibliography\{…\}" {
  128.                     # find .aux and open base .tex/.ltx
  129.                     set base [lindex [split $base_aux "."] 0]
  130.                     if [file exists ${base}.tex] {
  131.                         set base ${base}.tex
  132.                     } elseif [file exists ${base}.ltx] {
  133.                         set base ${base}.ltx
  134.                     } else {
  135.                         error "Base file with name '${base}.xxx' not found." 
  136.                     }                                   
  137.                     openFileQuietly ${base}
  138.                     
  139.                     # find bibliography, position cursor and add
  140.                     endOfBuffer
  141.                     if [catch {set pos [search -f 0 "\\bibliography\{" [getPos]]}] {
  142.                         # add the environment
  143.                         set pos [search -f 0 "\\end\{document\}" [getPos]]
  144.                         goto [lindex $pos 0]
  145.                         set preinsert "\\bibliography\{"
  146.                         set postinsert "\}\r\r"
  147.                     } else {
  148.                         set preinsert ""
  149.                         set postinsert ","
  150.                         goto [lindex $pos 1]
  151.                     }
  152.                     set bibfile [bibPickBibliography 0 \
  153.                         "Select a bibliography file to add"]
  154.                     insertText "${preinsert}[lindex [split $bibfile "."] 0]${postinsert}"
  155.                         
  156.                 }
  157.                 "Cancel" {
  158.                     # nothing
  159.                 }
  160.               }               
  161.               return
  162.           } else {
  163.               # go to a current entry
  164.               bibGotoEntry $item
  165.               beep
  166.               message "Warning--$warning $item"
  167.               return
  168.           }
  169.       }
  170.       default {
  171.           bib_GotoError $msg
  172.       }
  173.     } 
  174. }
  175.  
  176. ## 
  177.  # -------------------------------------------------------------------------
  178.  #     
  179.  # "bib_GotoError" --
  180.  #    
  181.  #    Parse and goto a specific error    in a particular    file.  Look    locally    for
  182.  #    the    correct    text in    case we've edited the file.
  183.  # -------------------------------------------------------------------------
  184.  ##
  185. proc bib_GotoError {msg} {
  186.       # it's an error.  Extract type, line, filename, and position of error
  187.       set errtype [lindex [split $msg "-"] 0]
  188.       if ![regsub {.*line ([0-9]+) .*} $msg {\1} line] {
  189.           error "Failed to parse line number from BibTeX error"
  190.       }
  191.     if ![regsub    {.*of file (.*) a .*} $msg {\1}    filename] {
  192.         error "Failed to parse filename    from BibTeX    error"
  193.     }
  194.     if ![regsub    {.*a '(.*)' at.*} $msg {\1}    problem] {
  195.         error "Failed to parse filename    from BibTeX    error"
  196.     }
  197.     if ![regsub    {.*at (.*)}    $msg {\1} linepos] {
  198.         error "Failed to parse line    position from BibTeX error"
  199.     }
  200.       openTeXFile $filename
  201.       goto [rowColToPos $line $linepos]
  202.     # Un-map the encoding we did on the other end.
  203.     regsub "‘" $problem "\{" problem
  204.     regsub "’" $problem "\}" problem
  205.     # Un-map the encoding we did on the other end.
  206.     regsub "‘" $errtype "\{" errtype
  207.     regsub "’" $errtype "\}" errtype
  208.     set pos [getPos]
  209.     set    t [getText [lineStart $pos]    $pos]
  210.     if {$t != $problem}    {
  211.         # we've    edited the file; look locally
  212.         set pr "^[quoteExpr2 $problem]"
  213.         if {![catch {search -f 0 -r 1 -l [expr $pos - 300] $pr $pos} found]} {
  214.             set pos [lindex $found 1]
  215.         } elseif {![catch {search -f 1 -r 1 -l [expr $pos + 300] $pr $pos} found]} {
  216.             set pos [lindex $found 1]
  217.         }            
  218.     }
  219.       select [lineStart $pos] $pos
  220.       beep
  221.       message "$errtype"
  222.       return
  223. }
  224.  
  225. ## 
  226.  # -------------------------------------------------------------------------
  227.  #     
  228.  # "TeXEnsureSearchPathSet"    --
  229.  #    
  230.  #    Make sure TeX mode has built our search    path, so we    can    find 
  231.  #    bibliography files.     Perhaps we    should have    our    own    variable
  232.  #    for    these?
  233.  # -------------------------------------------------------------------------
  234.  ##
  235. proc TeXEnsureSearchPathSet {} {
  236.     global TeXSearchPath
  237.     if { [llength $TeXSearchPath] == 0 } {
  238.         message "building TeX search path…"
  239.         set TeXSearchPath [buildTeXSearchPath]
  240.         message ""
  241.     }
  242. }
  243.  
  244. ## 
  245.  # -------------------------------------------------------------------------
  246.  #     
  247.  # "bibPickBibliography" --
  248.  #    
  249.  #    Put    up a list-dialog so    the    user can select    a bibliography file    for
  250.  #    some action    (taken by the caller).    Can    also create    a new file if
  251.  #    desired.
  252.  # -------------------------------------------------------------------------
  253.  ##
  254. proc bibPickBibliography {{allowNew 1} {prompt "Pick a bibliography file"}} {
  255.     set biblist [bibListAllBibliographies]
  256.     if $allowNew {
  257.         lappend biblist {New file…}
  258.     }
  259.     set bibfile [listpick -p $prompt $biblist]
  260.     if {$bibfile == ""} {
  261.         error "No bibliography file selected."
  262.     } elseif {$bibfile == "New file…" } {
  263.         set bibfile [putfile "Save new bibliography as…" ".bib"]
  264.         if {$bibfile == ""} {
  265.             error "No bibliography file selected."
  266.         } else {
  267.             set fout [open $bibfile w]
  268.             close $fout
  269.         }        
  270.     }    
  271.     return [file tail $bibfile]
  272. }
  273.  
  274. ## 
  275.  # -------------------------------------------------------------------------
  276.  #     
  277.  # "bibListAllBibliographies" --
  278.  #    
  279.  #    Return all bibliographies on the search    path.
  280.  # -------------------------------------------------------------------------
  281.  ##
  282. proc bibListAllBibliographies {} {
  283.     TeXEnsureSearchPathSet
  284.     global TeXSearchPath
  285.     foreach f $TeXSearchPath {
  286.         eval lappend biblist [glob -nocomplain ${f}*.bib]
  287.     }
  288.     return $biblist
  289. }
  290.  
  291. ## 
  292.  # -------------------------------------------------------------------------
  293.  #     
  294.  # "bibGotoEntry" --
  295.  #    
  296.  #    Look for a bib entry in    the    given list of files, or    if that    fails or
  297.  #    isn't given, look in all available bib files on    the    search path.
  298.  # -------------------------------------------------------------------------
  299.  ##
  300. proc bibGotoEntry {entry {biblist {}}} {
  301.     if ![catch {bib_GotoEntryFromIndex $entry}] {
  302.         return
  303.     }
  304.     if {[llength $biblist] && ![catch {bib_GotoEntry $entry $biblist}]} {
  305.         return
  306.     }
  307.     if ![catch {bib_GotoEntry $entry [bibListAllBibliographies]}] {
  308.         return
  309.     }
  310.     beep
  311.     error "Can't find entry '$entry' in the .bib file(s)"
  312. }
  313.  
  314. ## 
  315.  # -------------------------------------------------------------------------
  316.  #     
  317.  # "bib_GotoEntryFromIndex"    --
  318.  #    
  319.  #    Look in    the    bibIndex and find an entry very    quickly.
  320.  # -------------------------------------------------------------------------
  321.  ##
  322. proc bib_GotoEntryFromIndex {entry} {
  323.      set bibTopPat {@([a-zA-Z]+)[\{\(][     ]*}
  324.     global PREFS
  325.     # if it fails, but we succeed later, we will have the opportunity
  326.     # to rebuild the bibIndex
  327.     if [file exists "${PREFS}:bibIndex"] {
  328.         source "${PREFS}:bibIndex"
  329.         global bibIndex
  330.         foreach f [array names bibIndex] {
  331.             if [regexp "\[ \r\n\]$entry\[ \r\n\]" "$bibIndex($f)"] {
  332.                 openFileQuietly $f
  333.                 set p [search -f 1 -r 1 $bibTopPat$entry 0]
  334.                 eval select $p
  335.                 centerRedraw
  336.                 eval select $p
  337.                 unset bibIndex
  338.                 return
  339.             }
  340.         }
  341.         unset bibIndex
  342.     }
  343.     error "Entry '$entry' not found in bibIndex"
  344. }
  345.  
  346. ## 
  347.  # -------------------------------------------------------------------------
  348.  #     
  349.  # "bib_GotoEntry" --
  350.  #    
  351.  #    Find a bib entry in    one    of the given list of files,    and    signal an
  352.  #    error if the entry isn't found.     I think this is the quickest way.
  353.  # -------------------------------------------------------------------------
  354.  ##
  355. proc bib_GotoEntry {entry biblist} {
  356.      set bibTopPat {@([a-zA-Z]+)[\{\(][     ]*}
  357.      set cid [scancontext create]
  358.      scanmatch $cid $bibTopPat$entry {
  359.          set found "$matchInfo(subindex0)"
  360.      }
  361.      set found ""
  362.     foreach f $biblist {
  363.         message "Searching [file tail $f]…"
  364.         if {![catch {set fid [open $f]}]} {
  365.             scanfile $cid $fid
  366.             close $fid
  367.             if {$found != ""} {
  368.                 openFileQuietly $f
  369.                 eval select $found
  370.                 scancontext delete $cid
  371.                 global bib_AutoIndex
  372.                 # make the index since it was obviously out of date                
  373.                 if {$Bib_AutoIndex == 2 || [askyesno "The bibIndex is obviously out of date.  Rebuild?"]=="yes"} {
  374.                     bib_MakeIndex
  375.                 }
  376.                 return
  377.             }    
  378.         }
  379.     }
  380.     scancontext delete $cid
  381.     error "Entry '$entry' not found."
  382. }
  383.  
  384. ## 
  385.  # -------------------------------------------------------------------------
  386.  #     
  387.  # "bib_MakeIndex" --
  388.  #    
  389.  #    Build the bibIndex file    which allows for very fast lookup of bib
  390.  #    entries.
  391.  # -------------------------------------------------------------------------
  392.  ##
  393. proc bib_MakeIndex {} {
  394.     global PREFS 
  395.     set bibTopPat2 {^[     ]*@([a-zA-Z]+)[\{\(][     ]*([^=,     ]+)}    
  396.      set cid [scancontext create]
  397.      # this will actually mark strings as well
  398.      scanmatch $cid $bibTopPat2 {
  399.          if {[string tolower $matchInfo(submatch0)] != "string"} {
  400.              lappend found $matchInfo(submatch1)
  401.          }
  402.      }
  403.      set bout [open "${PREFS}:bibIndex" w]
  404.      puts $bout "# Bibliography index file for quick reference lookup"
  405.      puts $bout "# Created on [mtime [now]]"
  406.     foreach f [bibListAllBibliographies] {
  407.         set found {}
  408.         puts $bout "set \"bibIndex($f)\" \{"
  409.         message "Scanning [file tail $f]…"
  410.         if {![catch {set fid [open $f]}]} {
  411.             scanfile $cid $fid
  412.             close $fid
  413.         }
  414.         puts $bout $found
  415.         puts $bout "\}"
  416.     }
  417.     close $bout
  418.     scancontext delete $cid
  419.     message "bibIndex creation complete"
  420. }
  421.